package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.common.constants.search.SearchConstants;
import com.heima.common.exception.CustException;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.pojos.ApUser;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.ArticleSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

@Slf4j
@Service
public class ArticleSearchServiceImpl implements ArticleSearchService {
    @Autowired
    ApUserSearchService apUserSearchService;
    @Autowired
    RestHighLevelClient restHighLevelClient;
    @Value("${file.minio.readPath}")
    String readPath;
    @Override
    public ResponseResult search(UserSearchDto userSearchDto) {
        //1.检查参数
        if (StringUtils.isBlank(userSearchDto.getSearchWords())) {
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        if (userSearchDto.getMinBehotTime()==null) {
            userSearchDto.setMinBehotTime(new Date());
        }
        if (userSearchDto.getPageSize()<1) {
            userSearchDto.setPageSize(10);
        }

        // 如果是首页记录搜索关键字
        ApUser user = AppThreadLocalUtils.getUser();
        if (userSearchDto.getFromIndex()==0) {
            userSearchDto.setEntryId(user==null?null:user.getId());
            apUserSearchService.insert( userSearchDto);
        }


        //2.构建SearchRequest请求
        SearchRequest searchRequest = new SearchRequest(SearchConstants.ARTICLE_INDEX_NAME);
        //2.1构建SearchSourceBuilder
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //2.2通过builder构建查询条件 .query
            //创建bool条件  .must
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //关键词match（分词查询）
        boolQueryBuilder.must(QueryBuilders.matchQuery("title",userSearchDto.getSearchWords()));
        //最小时间range （范围查询）
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("publishTime").lt(userSearchDto.getMinBehotTime()));
        builder.query(boolQueryBuilder);
        //2.3通过builder构建高亮条件 1.哪个字段高亮 title 2.加前缀标签 3.后缀标签
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");
        highlightBuilder.postTags("</font>");
        builder.highlighter(highlightBuilder);
        //2.4通过builder构建分页条件 from（0） size（）
        builder.from(0);
        builder.size(userSearchDto.getPageSize());
        //2.5通过builder构建排序条件 sort 发布时间 降序
        builder.sort("publishTime", SortOrder.DESC);
        searchRequest.source(builder);
        //3客户端执行search搜索方法
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //4解析响应结果SearchResponse
            SearchHits hits = searchResponse.getHits();
            System.out.println("数量："+hits.getTotalHits().value);
            //查询文章列表
            SearchHit[] searchHitsList = hits.getHits();
            ArrayList<SearchArticleVo> list = new ArrayList<>();
            for (SearchHit doc : searchHitsList) {
                //获取文章内容
                String articleJsonString = doc.getSourceAsString();
                SearchArticleVo searchArticleVo = JSON.parseObject(articleJsonString, SearchArticleVo.class);
                //获取高亮条件  key：高亮字段  value：高亮结果
                Map<String, HighlightField> highlightFields = doc.getHighlightFields();
                HighlightField highlightField = highlightFields.get("title");
                if (highlightField!=null) {
                    //拼接高亮结果
                    Text[] fragments = highlightField.getFragments();
                    String join = StringUtils.join(fragments);
                    searchArticleVo.setTitle(join);
                }
                list.add(searchArticleVo);
            }
            //给static静态页面添加前缀
            if (CollectionUtils.isNotEmpty(list)) {
                for (SearchArticleVo searchArticleVo : list) {
                    searchArticleVo.setStaticUrl(readPath+searchArticleVo.getStaticUrl());
                }
            }
            return ResponseResult.okResult(list);
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
        }
    }
    @Override
    public void saveArticle(SearchArticleVo article) {
        IndexRequest request = new IndexRequest(SearchConstants.ARTICLE_INDEX_NAME);
        request.id(String.valueOf(article.getId()));
        request.source(JSON.toJSONString(article), XContentType.JSON);
        try {
            restHighLevelClient.index(request,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("索引库添加文章数据失败: {}",article);
        }
    }
    @Override
    public void deleteArticle(Long articleId) {
        DeleteRequest request = new DeleteRequest(SearchConstants.ARTICLE_INDEX_NAME,String.valueOf(articleId));
        try {
            restHighLevelClient.delete(request,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("删除文章失败 原因:{}",e.getMessage());
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR);
        }
    }
}
